#include <QFileDialog>
#include <QMessageBox>
#include <QTreeWidget>
#include <QTextStream>
#include <QProcess>
#include <QTime>

#include "ODBToolkit.h"
#include "ioODB.h"
#include "ioCGNS.h"

void loadStyleSheet(QString qssName = "")
{
	if (qssName == "")
		qssName = QCoreApplication::applicationDirPath() + "/odb.qss";
	QFile data(qssName);
	QString qssFile;

	if (data.open(QFile::ReadOnly))
	{
		QTextStream styleIn(&data);
		qssFile = styleIn.readAll();
		data.close();
		qApp->setStyleSheet(qssFile);
	}
}

ODBToolkit::ODBToolkit(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);
	initUi();

	//
	dialog_partition = std::make_shared<QDialog>(this);
	ui_partition.setupUi(dialog_partition.get());

	// 
	ui.treeWidget->clear();
	ui.treeWidget->header()->setHidden(true);
	ui.treeWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
	connect(ui.treeWidget, SIGNAL(customContextMenuRequested(const QPoint&)), 
		this, SLOT(on_treeWidget_rightClicked(const QPoint&)));

	//
	loadStyleSheet();

	//
	ui.splitter->setStretchFactor(0, 1);
	ui.splitter->setStretchFactor(1, 2);

	//
	ui.textEdit->setLineWrapMode(QTextEdit::NoWrap);

	//
	simu = std::make_shared<KSimulation>();

	//
	qout = std::make_shared<QRedirectStream>(std::cout, ui.textEdit);
	connect(qout.get(), SIGNAL(sendString(const QString &)), ui.textEdit, SLOT(append(const QString &)));

	//
	meshIO = std::make_shared<MeshIOWorker>(this, simu);
	meshIO->moveToThread(&readerThread);
	readerThread.start();
	connect(this, SIGNAL(meshReaderWriter(const QString &, const QString &)),
		meshIO.get(), SLOT(meshReaderWriter(const QString &, const QString &)));
	connect(meshIO.get(), SIGNAL(showMessage(const QString &, int)),
		ui.statusBar, SLOT(showMessage(const QString &, int)));
	connect(meshIO.get(), SIGNAL(finished(const QString &, int)),
		this, SLOT(onThread_finished(const QString &, int)));

	//
	hdfView = std::make_shared<QProcess>(this);
	connect(hdfView.get(), SIGNAL(readyRead()), this, SLOT(onProcess_readyRead()));
}

void ODBToolkit::initUi(int_t opp)
{
	if (opp == 0) {
		ui.actionNew->setEnabled(true);
		ui.actionSave->setEnabled(false);
		ui.actionTecplot_ASCII->setEnabled(false);
		ui.actionDTF->setEnabled(false);
		ui.actionClose->setEnabled(false);
		ui.treeWidget->setVisible(false);
	}
	else if(opp == 1) {
		ui.actionNew->setEnabled(false);
		ui.actionSave->setEnabled(true);
		ui.actionTecplot_ASCII->setEnabled(true);
		ui.actionDTF->setEnabled(true);
		ui.actionClose->setEnabled(true);
		ui.treeWidget->setVisible(true);
	}
}

QStringList getSelectedFiles(QString &titles, QString &nameFilter, QString dir,
	QFileDialog::FileMode fileModel, QFileDialog::AcceptMode acceptMode)
{
	QFileDialog fd;
	fd.setWindowTitle(titles);
	fd.setDirectory(dir);
	fd.resize(600, 400);
	fd.setNameFilter(nameFilter);
	fd.setViewMode(QFileDialog::Detail);
	fd.setFileMode(fileModel);
	fd.setAcceptMode(acceptMode);
	fd.setWindowFlags(fd.windowFlags() |= Qt::WindowCloseButtonHint);
	fd.setWhatsThis(titles);

	QStringList selectedFiles;
	if (fd.exec() == QDialog::Accepted) {
		selectedFiles = fd.selectedFiles();
	}
	else {
		fd.close();
	}

	return selectedFiles;
}

void ODBToolkit::on_actionNew_triggered()
{
	fileName = getSelectedFiles(
		QString("Save ODB File"),
		QString("ODB File (*.odb *.ODB)"), QString(""),
		QFileDialog::AnyFile, QFileDialog::AcceptSave)[0];

	if (QFileInfo(fileName).suffix() != "odb" &&
		QFileInfo(fileName).suffix() != "ODB") {
		fileName += ".odb";
	}

	initUi(1);
	this->setWindowTitle(QString("ODBToolkit : ") + fileName);	
}

void ODBToolkit::on_actionOpen_triggered()
{
	if (!fileName.isEmpty() || simu->zones.size() != 0) {
		switch (QMessageBox::question(this,
			"Open ODB ...",
			"ODB file already exist, close it and continue ?",
			QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Ok))
		{
		case QMessageBox::Ok:
			on_actionClose_triggered();
			break;		
		case QMessageBox::Cancel: default:
			return;
			break;
		}
	}

	QStringList selectedFiles = getSelectedFiles(
		QString("Open ODB File"),
		QString("ODB File (*.odb *.ODB"), QString(""),
		QFileDialog::AnyFile, QFileDialog::AcceptOpen);
	if (selectedFiles.size() == 0) return;

	fileName = selectedFiles[0];

	if (QFileInfo(fileName).suffix() == "odb" || 
		QFileInfo(fileName).suffix() == "ODB") {
		emit meshReaderWriter(fileName, QString("Read:ODB"));
	}	
}

void ODBToolkit::on_actionOpenFOAM_triggered()
{
	QStringList selectedFiles = getSelectedFiles(
		QString("Import from OpenFOAM polyMesh folder"),
		QString(""), QString(""),
		QFileDialog::Directory, QFileDialog::AcceptOpen);
	if (selectedFiles.size() == 0) return;

	if (simu->zones.size() != 0) {
		switch (QMessageBox::information(this,
			"Import OpenFOAM ...",
			"Simulation zone already exist : \n  Click 'Ok' to append simulation zone;\n  Click 'Reset' to replace simulation zone.",
			QMessageBox::Ok | QMessageBox::Reset | QMessageBox::Cancel, QMessageBox::Ok))
		{
		case QMessageBox::Ok:
			break;
		case QMessageBox::Reset:
			simu->zones.swap(std::vector<KZoneShaPtr>());
			break;
		case QMessageBox::Cancel: default:		
			return;	break;
		}		
	}	
	
	emit meshReaderWriter(selectedFiles[0], QString("Read:OpenFOAM"));	
}

void ODBToolkit::on_actionCGNS_triggered()
{
	QStringList selectedFiles = getSelectedFiles(
		QString("Import CGNS..."),
		QString("*.CGNS *.cgns"), QString(""),
		QFileDialog::AnyFile, QFileDialog::AcceptOpen);
	if (selectedFiles.size() == 0) return;

	if (simu->zones.size() != 0) {
		switch (QMessageBox::information(this, 
			"Import cgns ...", 
			"Simulation zone already exist : \n  Click 'Ok' to append simulation zone;\n  Click 'Reset' to replace simulation zone.",
			QMessageBox::Ok | QMessageBox::Reset| QMessageBox::Cancel, QMessageBox::Ok))
		{
		case QMessageBox::Ok:
			break;
		case QMessageBox::Reset:
			simu->zones.swap(std::vector<KZoneShaPtr>());
			break;
		case QMessageBox::Cancel: default:		
			return;	break;
		}		
	}

	emit meshReaderWriter(selectedFiles[0], QString("Read:cgns"));
}

void ODBToolkit::on_actionSave_triggered()
{	
	if (fileName.isEmpty()) {
		fileName = getSelectedFiles(
			QString("Save ODB File"),
			QString("ODB File (*.odb *.ODB)"), QString(""),
			QFileDialog::AnyFile, QFileDialog::AcceptSave)[0];

		if (QFileInfo(fileName).suffix() != "odb" &&
			QFileInfo(fileName).suffix() != "ODB") {
			fileName += ".odb";
		}
	}	

	//
	if (simu->zones.size() == 0) return;

	//
	emit meshReaderWriter(fileName, QString("Save:ODB"));	
} 

void ODBToolkit::on_actionClose_triggered()
{
	fileName.clear();
	ui.treeWidget->clear();
	simu->zones.swap(std::vector<KZoneShaPtr>());
	initUi();
}

void ODBToolkit::on_actionTecplot_ASCII_triggered()
{
	QStringList selectedFiles = getSelectedFiles(
		QString("Save Tecplot ASCII File"),
		QString("All Data(*.*);;Tecplot File (*.dat *.plt)"), QString(""),
		QFileDialog::AnyFile, QFileDialog::AcceptSave);
	if (selectedFiles.size() == 0) return;

	emit meshReaderWriter(selectedFiles[0], QString("Write:Tecplot"));
}

void ODBToolkit::on_actionHDFVIEW_triggered()
{
	QString hdfviewName = QCoreApplication::applicationDirPath() + "/HDFView/HDFView.bat";
	if (QFileInfo(hdfviewName).exists()) {
		hdfView.get()->start(hdfviewName);
		if (!hdfView.get()->waitForStarted()) {
			std::cout << "\nERROR : start " << hdfviewName.toStdString() << " failed." << std::endl;
			ui.statusBar->clearMessage();
		}		
	}
	else {
		QMessageBox::critical(this,
			"Launch HDFView",
			QString("ERROR : File does not exist.\nCheck file : ") + hdfviewName,
			QMessageBox::Cancel, QMessageBox::Cancel);
	}
}

void ODBToolkit::on_actionDTF_triggered()
{
	QStringList selectedFiles = getSelectedFiles(
		QString("Export to DTF File"),
		QString("DTF File (*.DTF *.dtf);;All Data(*.*)"), QString(""),
		QFileDialog::AnyFile, QFileDialog::AcceptSave);
	if (selectedFiles.size() == 0) return;

	emit meshReaderWriter(selectedFiles[0], QString("Write:DTF"));
}

void ODBToolkit::on_actionCombine_triggered()
{
	ivector sels;

	if (selectBoundaries(sels) > 1) {//combine bc
		//
		int_t iz = ui.treeWidget->topLevelItem(0)->indexOfChild(
			ui.treeWidget->selectedItems()[0]->parent()->parent());
		//
		simu->zones[iz]->combineBoundary(sels);
		//
		updateTreeWidget();
	}
}

void ODBToolkit::on_actionPartition_triggered()
{
	if (dialog_partition->exec() == QDialog::Accepted) {
		//
		auto selItems = ui.treeWidget->selectedItems();
		//
		ivector selzones;
		if (selectZones(selzones) == 1) {
			//
			QString mess =
				QString("Decomposing zone '") +
				simu->zones[selzones[0]]->getName().c_str() + "' to " +
				QString::number(ui_partition.spinBox->value()) + " parts ... ";
			//
			ui.statusBar->showMessage(mess);
			//
			simu->zones[selzones[0]]->metisDecompose(ui_partition.spinBox->value());
			//
			updateTreeWidget();
			//
			ui.statusBar->showMessage(mess + "done.", 3000);
		}
		else if (selItems.size() == 1 && selItems[0]->text(0) == "Simulation 1") {
			//
			int_t nparts = ui_partition.spinBox->value();
			if (nparts < simu->zones.size()) {
				QMessageBox::warning(NULL, 
					"Warning", 
					QString() + "Number of parts : " + QString::number(nparts) + 
					            " must be great than or equal to zone size : " + 
					            QString::number(simu->zones.size()),
					QMessageBox::Cancel, QMessageBox::Cancel);
				return;
			}
			//
			QString mess =
				QString("Decomposing simulation to ") +				
				QString::number(ui_partition.spinBox->value()) + " parts ... ";
			ui.statusBar->showMessage(mess);
			//
			simu->zoneBasedDecompose(nparts);
			//
			updateTreeWidget();
			//
			ui.statusBar->showMessage(mess + "done.", 3000);
		}
	}
}

void ODBToolkit::on_actionRename_triggered()
{
	auto curItem = ui.treeWidget->currentItem();
	if (curItem != nullptr && (curItem->flags() & (Qt::ItemIsEditable))) {
		ui.treeWidget->editItem(curItem, 0);
	}
}

void ODBToolkit::on_actionShowInfo_triggered()
{
	auto curItem = ui.treeWidget->currentItem();
	if (curItem == nullptr) return;

	if (curItem->text(0) == "Simulation 1") {
		simu->ouputInfo();
	}
	else if (curItem->parent() != nullptr && curItem->parent()->text(0) == "Simulation 1") {
		simu->zones[curItem->parent()->indexOfChild(curItem)]->ouputInfo();
	}
	else if (curItem->text(0) == "Boundaries") {
		int_t iz = curItem->parent()->parent()->indexOfChild(curItem->parent());
		std::cout << "\nBoundaries in zone '" << simu->zones[iz]->getName() << "'\n";
		for (int ibc = 0; ibc < simu->zones[iz]->getNumBoundaries(); ibc++) {
			simu->zones[iz]->getBoundary(ibc)->ouputInfo();
		}
	}
	else if (curItem->parent() != nullptr && curItem->parent()->text(0) == "Boundaries") {
		int_t iz = ui.treeWidget->topLevelItem(0)->indexOfChild(
			curItem->parent()->parent());
		int_t ibc = curItem->parent()->indexOfChild(curItem);
		std::cout 
			<< "\nBoundary '"<< simu->zones[iz]->getBoundary(ibc)->name 
			<< "' in zone '" << simu->zones[iz]->getName() << "'\n";
		simu->zones[iz]->getBoundary(ibc)->ouputInfo("  ");
	}
	else if (curItem->text(0) == "Partition") {
		int_t iz = ui.treeWidget->topLevelItem(0)->indexOfChild(curItem->parent());
		std::cout << std::endl
			<< simu->zones[iz]->getNumPartZone() 
			<<" partitions in zone '" << simu->zones[iz]->getName() << "'\n";
		for(int_t ip=0; ip<simu->zones[iz]->getNumPartZone(); ip++)
			simu->zones[iz]->getPartZone(ip)->ouputInfo();
	}
	else if (curItem->parent() != nullptr && curItem->parent()->text(0) == "Partition") {
		int_t iz = ui.treeWidget->topLevelItem(0)->indexOfChild(
			curItem->parent()->parent());
		int_t ip = curItem->parent()->indexOfChild(curItem);
		simu->zones[iz]->getPartZone(ip)->ouputInfo();
	}
}

void ODBToolkit::on_actionQuit_triggered()
{
	on_actionClose_triggered();
	QApplication::quit();
}

void ODBToolkit::on_actionDeleteZone_triggered()
{
	auto curItem = ui.treeWidget->currentItem();
	if (curItem == nullptr) return;

	if (curItem->parent() != nullptr && curItem->parent()->text(0) == "Simulation 1") {
		int_t iz = curItem->parent()->indexOfChild(curItem);
		simu->zones.erase(simu->zones.begin() + iz);
		//
		updateTreeWidget();
	}
}

int ODBToolkit::odbReader(const H5std_string& fileName)
{
	try
	{
		std::cout << "\nReading odb : " << fileName << " ... " << std::endl;

		/*
		 * Turn off the auto-printing when failure occurs so that we can
		 * handle the errors appropriately
		 */
		H5::Exception::dontPrint();

		//
		H5::H5File file(fileName, H5F_ACC_RDWR);

		// all data default in 'Simulation'
		H5::Group simGroup = file.openGroup("Simulation");

		//
		svector zoneNames;
		read_strings(simGroup, "zoneNames", zoneNames);

		//
		for (auto zName : zoneNames) {
			//
			auto zone = std::make_shared<KPolyZone>(simu.get());
			zone->setName(zName);
			zone->setIndex(simu->zones.size());

			//
			H5::Group zoneGroup = simGroup.openGroup(zName);

			//
			zone->readHDF5(zoneGroup);
			
			//
			zoneGroup.close();

			//
			simu->zones.push_back(zone);
		}

		//
		simGroup.close();
		file.close();

		std::cout << "Done." << std::endl;

		return ODB_OK;  // successfully terminated
	}
	// catch failure caused by the H5File operations
	catch (H5::FileIException error)
	{
		error.printErrorStack();
		return ODB_ERROR;
	}
	// catch failure caused by the DataSet operations
	catch (H5::DataSetIException error)
	{
		error.printErrorStack();
		return ODB_ERROR;
	}
	// catch failure caused by the DataSpace operations
	catch (H5::DataSpaceIException error)
	{
		error.printErrorStack();
		return ODB_ERROR;
	}
	// catch failure caused by the DataSpace operations
	catch (H5::DataTypeIException error)
	{
		error.printErrorStack();
		return ODB_ERROR;
	}	
}

int ODBToolkit::odbWriter(const H5std_string& fileName)
{
	using namespace H5;

	try
	{
		std::cout << "\nWriting odb : " << fileName << " ... " <<std::endl;

		/*
		* Turn off the auto-printing when failure occurs so that we can
		* handle the errors appropriately.
		*/
		Exception::dontPrint();

		// Create a new file using the default property lists.
		// H5::H5F_ACC_TRUNC : create a new file or overwrite an existing file.
		H5File file(fileName, H5F_ACC_TRUNC);

		// version
		string_t version("1.0.0");
		write_dataset(file, "ODB_version", version.size(), &version[0]);

		// Create a group under root '/'.
		Group simGroup(file.createGroup("Simulation"));

		//
		svector zoneNames;
		for (auto zone : simu->zones) {
			zoneNames.push_back(zone->getName());
		}
		write_strings(simGroup, "zoneNames", zoneNames);

		//
		for (auto zone : simu->zones) {

			// Create a group for this zone 
			Group zoneGroup(simGroup.createGroup(zone->getName()));

			//
			zone->writeHDF5(zoneGroup);

			//
			zoneGroup.close();
		}

		//
		simGroup.close();
		file.close();

		std::cout << "Done." << std::endl;
	}
	// catch failure caused by the H5File operations
	catch (H5::FileIException error)
	{
		error.printErrorStack();
		return -1;
	}
	// catch failure caused by the DataSet operations
	catch (H5::DataSetIException error)
	{
		error.printErrorStack();
		return -1;
	}
	// catch failure caused by the DataSpace operations
	catch (H5::DataSpaceIException error)
	{
		error.printErrorStack();
		return -1;
	}
	// catch failure caused by the DataType operations
	catch (H5::DataTypeIException error)
	{
		error.printErrorStack();
		return -1;
	}
	catch (...)
	{
		return -1;
	}
	return 0;  // successfully terminated
}

void ODBToolkit::onProcess_readyRead()
{
	ui.textEdit->append(((QProcess *)sender())->readAll());
}

void ODBToolkit::updateTreeWidget()
{
	ui.treeWidget->clear();
	ui.treeWidget->setColumnCount(1);
	ui.treeWidget->header()->setHidden(true);

	QTreeWidgetItem* simItem =
		new QTreeWidgetItem(ui.treeWidget, QStringList(QString("Simulation 1")));
	simItem->setIcon(0, QIcon(QStringLiteral(":/ODBToolkit/simulation.png")));
	simItem->setExpanded(true);	

	for (int iz = 0; iz < simu->zones.size(); iz++) {
		//
		auto &zone = simu->zones[iz];

		//
		QTreeWidgetItem* zoneItem = new QTreeWidgetItem(
			simItem, QStringList(QString(zone->getName().c_str())));
		zoneItem->setIcon(0, QIcon(QStringLiteral(":/ODBToolkit/zone.png")));
		zoneItem->setExpanded(true);
		zoneItem->setFlags(zoneItem->flags() | Qt::ItemIsEditable);

		//
		QTreeWidgetItem* bcsItem = new QTreeWidgetItem(
			zoneItem, QStringList(QString("Boundaries")));
		bcsItem->setIcon(0, QIcon(QStringLiteral(":/ODBToolkit/folder.png")));
		bcsItem->setExpanded(true);
		
		//
		for (int ibc = 0; ibc < zone->getNumBoundaries(); ibc++) {
			//
			KBoundary &bc = *zone->getBoundary(ibc);
			//
			QTreeWidgetItem* bcItem = new QTreeWidgetItem(
				bcsItem, QStringList(QString(bc.name.c_str())));
			bcItem->setIcon(0, QIcon(QStringLiteral(":/ODBToolkit/boundary.png")));
			bcItem->setFlags(bcItem->flags() | Qt::ItemIsEditable);
		}

		//
		if (simu->zones[iz]->getNumPartZone() != 0) {

			QTreeWidgetItem* partsItem = new QTreeWidgetItem(
				zoneItem, QStringList(QString("Partition")));
			partsItem->setIcon(0, QIcon(QStringLiteral(":/ODBToolkit/folder.png")));
			partsItem->setExpanded(true);

			for (int ip = 0; ip < simu->zones[iz]->getNumPartZone(); ip++) {
				QTreeWidgetItem* partItem = new QTreeWidgetItem(
					partsItem, QStringList(QString("part ")+ QString::number(ip)));
				partItem->setIcon(0, QIcon(QStringLiteral(":/ODBToolkit/partitionZone.png")));
			}
		}		
	}	
}

void ODBToolkit::on_treeWidget_rightClicked(const QPoint &point)
{
	QTreeWidgetItem* curItem = ui.treeWidget->currentItem();  
	if (curItem == NULL)return;

	QMenu menu(this);

	if(ui.treeWidget->selectedItems().size() == 1)
		menu.addAction(ui.actionShowInfo);

	if (curItem->text(0) == "Simulation 1") {
		menu.addSeparator();
		menu.addAction(ui.actionPartition);		
	}	
	else if (curItem->parent() != nullptr &&
		curItem->parent()->text(0) == "Boundaries")// zone bc
	{
		if (selectBoundaries() >= 2) {
			menu.addSeparator();
			menu.addAction(ui.actionCombine);			
		}
		else if (selectBoundaries() == 1) {
			menu.addSeparator();
			menu.addAction(ui.actionRename);			
		}
	}
	else if (curItem->parent() != nullptr &&
		curItem->parent()->text(0) == "Simulation 1") // zone
	{
		if (selectZones() >= 2) {
			//menu.addAction(ui.actionCombine);
		}		
		else if (selectZones() == 1) {
			menu.addSeparator();
			menu.addAction(ui.actionRename);
			menu.addSeparator();
			menu.addAction(ui.actionPartition);
			menu.addSeparator();
			menu.addAction(ui.actionDeleteZone);
		}
	}

	QPoint pos;
	menu.exec(QCursor::pos());
}

void ODBToolkit::on_treeWidget_itemChanged(QTreeWidgetItem *item, int column)
{
	if (item == nullptr) return;

	QString newName = item->text(column);

	if (item->parent() && item->parent()->text(0) == "Simulation 1") {
		int_t iz = item->parent()->indexOfChild(item);
		simu->zones[iz]->setName(newName.toLocal8Bit().data());
	}
	else if (item->parent() && item->parent()->text(0) == "Boundaries") {
		int_t iz = ui.treeWidget->topLevelItem(0)->indexOfChild(item->parent()->parent());
		int_t ibc= item->parent()->indexOfChild(item);
		simu->zones[iz]->getBoundary(ibc)->name = newName.toLocal8Bit().data();
	}
}

int_t ODBToolkit::selectBoundaries(ivector &bcs)
{
	{ bcs.swap(ivector()); }

	auto selItems = ui.treeWidget->selectedItems();
	if (selItems.size() == 0) 
	{		
		return -1;
	}
	else {
		auto bcItem = selItems[0]->parent();
		if (bcItem != nullptr && bcItem->text(0) == "Boundaries") {
			for (auto &it : selItems) {
				if (it->parent() == bcItem) {
					bcs.push_back(bcItem->indexOfChild(it));
				}
				else {
					bcs.clear();
					return -1;
				}
			}
			return bcs.size();
		}
		else {
			return -1;
		}
	}
}

int_t ODBToolkit::selectZones(ivector &zones)
{
	{ zones.swap(ivector()); }

	auto selItems = ui.treeWidget->selectedItems();
	if (selItems.size() == 0)
	{
		return -1;
	}
	else {
		auto simItem = selItems[0]->parent();
		if (simItem != nullptr && simItem->text(0) == "Simulation 1") {
			for (auto &it : selItems) {
				if (it->parent() == simItem) {
					zones.push_back(simItem->indexOfChild(it));
				}
				else {
					zones.clear();
					return -1;
				}
			}
			return zones.size();
		}
		else {
			return -1;
		}
	}
}

void ODBToolkit::onThread_finished(const QString &pipe, int status)
{
	if (pipe == "Read:cgns") {
		updateTreeWidget();
		initUi(1);
	}
	else if (pipe == "Read:OpenFOAM") {
		updateTreeWidget();
		initUi(1);
	}
	else if (pipe == "Read:ODB") {
		updateTreeWidget();
		initUi(1);
		setWindowTitle(QString("ODBToolkit : ") + fileName);
	}
	else if (pipe == "Save:ODB") {
		setWindowTitle(QString("ODBToolkit : ") + fileName);
	}	
}

void MeshIOWorker::meshReaderWriter(const QString &fileName, const QString &typeName)
{
	QTime time;	time.start();	

	QString message;
	if (typeName == "Read:cgns") {
		//
		message = QString("Reading cgns : ") + fileName + "...";
		emit showMessage(message);
		//
		cgns::CGNSMeshReader cgnsReader(fileName.toLocal8Bit().data());
		//
		if (cgnsReader.getErrorCode() == CG_OK) {
			//
			simu->convertFrom(&cgnsReader);
			//
			emit finished(typeName, ODB_OK);
		}		
	}
	else if (typeName == "Read:OpenFOAM") {
		//
		message = QString("Reading OpenFOAM : ") + fileName + "...";
		emit showMessage(message);
		//		
		auto zone = std::make_shared<KPolyZone>(simu.get());
		if (zone->importOpenFOAM(fileName.toLocal8Bit().data()) == ODB_OK) {
			zone->setName(string_t("zone_") + std::to_string(simu->zones.size() + 1));
			zone->setIndex(simu->zones.size());
			//		
			simu->zones.push_back(zone);
			//
			emit finished(typeName, ODB_OK);
		}
	}
	else if (typeName == "Write:Tecplot") {
		//
		message = QString("Writing tecplot : ") + fileName + "...";
		emit showMessage(message);
		//
		simu->exportToTecplotASCII(fileName.toLocal8Bit().data());
	}
	else if (typeName == "Read:ODB") {
		//
		message = QString("Reading ODB : ") + fileName + "...";
		emit showMessage(message);
		//
		if (mainWin->odbReader(fileName.toLocal8Bit().data()) == ODB_OK) {
			emit finished(typeName, ODB_OK);
		}
	}
	else if (typeName == "Save:ODB") {
		//
		message = QString("Saving ODB : ") + fileName + "...";
		emit showMessage(message);
		//
		if (mainWin->odbWriter(fileName.toLocal8Bit().data()) == ODB_OK) {
			emit finished(typeName, ODB_OK);
		}		
	}
	else if (typeName == "Write:DTF") {
		//
		message = QString("Writing DTF : ") + fileName + "...";
		emit showMessage(message);
		//
		simu->exportDTF(fileName.toLocal8Bit().data());
	}

	emit showMessage(message + "done(" +
		QString::number(time.elapsed() / 1000.0)+"s)", 3000);
}

